using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using Unity.VisualScripting.FullSerializer;
using UnityEngine;

public class HitService : FSMServiceiBase
{
    public override void OnBegin(PlayerState state)
    {
        base.OnBegin(state);
        hit_targets.Clear();
        last_end = Vector3.zero;
        ReSetAllExcuted();
    }



    public override void OnEnd(PlayerState state)
    {
        base.OnBegin(state);
        ReSetAllExcuted();
    }

    public override void OnUpdate(float normalizedTime, PlayerState state)
    {
        base.OnUpdate(normalizedTime, state);
        var configs = state.stateEntity.hitConfigs;
        if(configs != null && configs.Count>0)
        {
            for(int i = 0;i < configs.Count; i++)
            {
                var e = configs[i];
                if(normalizedTime >= e.trigger && normalizedTime<=e.end)
                {
                    hit_targets.Clear();
                    Do(e, state);
                }
            }
        }

    }


    Vector3 last_end;

    private void Do(HitConfig e, PlayerState state)
    {
        var obj = player.GetHangPoint(e.begin);
        UnityEngine.Vector3 begin = obj.transform.position;
        
        //UnityEngine.Vector3 begin = e.point.position;
        //UnityEngine.Vector3 end = begin + e.point.forward * e.length;

        if (e.type == 0) //phy
        {
            UnityEngine.Vector3 end = begin + obj.transform.forward * e.length;
            if(last_end == Vector3.zero)
            {
                LineCast(begin, end, e, state);
            }
            else
            {
                int count = 3;
                int cur_state_id = player.currentState.id;
                for(int i = 0; i < count; i++)
                {
                    Vector3 end2 = Vector3.Lerp(last_end, end, i / count);
                    LineCast(begin, end2, e, state);
                    if (cur_state_id != player.currentState.id)  //切状态就不要继续检测了 留给下一个状态检测
                        return;
                }
            }
            last_end = end;


        }
        else if (e.type == 1)
        {

            Boxcast(obj.transform, e, state);
        }
    }

    RaycastHit[] raycastHits = null;
    private void Boxcast(Transform begin, HitConfig e, PlayerState state)
    {
        if(raycastHits == null)
            raycastHits = new RaycastHit[30];

        var count = Physics.BoxCastNonAlloc(begin.position + begin.transform.TransformDirection(e.box_center), 
            e.box_size, begin.forward, raycastHits, begin.rotation, 
            e.length, player.GetEnemyLayerMask(), QueryTriggerInteraction.Collide);

        //Debug.DrawLine(begin.position, begin.transform.TransformDirection(e.box_center), Color.red, 0.2f);

        if (count > 0)
        {
            for(int i = 0; i < count; i++)
            {
                RaycastHit hit = raycastHits[i];
                var fsm = hit.transform.GetComponent<FSM>();
                if (hit.transform.CompareTag(GameDefine.WeaponTag))
                {
                    OnBeBlock(hit, fsm);
                }
                else
                {
                    OnHit(begin.position, e, state, hit, fsm);
                }
            }
        }
    }

    //记录某个东西是否被击中过 避免多次计算碰撞
    List<int> hit_targets = new List<int>();
    //是否命中


    public bool LineCast(Vector3 begin,Vector3 end,HitConfig config,PlayerState state)
    {
        //表示碰到 collide 都算碰撞
        Debug.DrawLine(begin, end, Color.red, 0.2f);
        var result = Physics.Linecast(begin, end, out var hitInfo, player.GetEnemyLayerMask(),QueryTriggerInteraction.Collide);
        if(result)
        {
            //表示人物碰到的 怪物 处于武器格挡 状态         
            var fsm = hitInfo.transform.GetComponentInParent<FSM>();
            var d = Vector3.Distance(fsm._transform.position, player._transform.position);
            var f = fsm._transform.ForwardOrBack(player._transform.position);
            //这个地方有问题

            
            if (hitInfo.transform.CompareTag(GameDefine.WeaponTag))
            {
                OnBeBlock(hitInfo, fsm);
                //6、血条？不知道处理不
            }
            else if (fsm.IsBlockState() && f > 0 && d <= state.skill.block_distance)
            {
                OnBeBlock(hitInfo, fsm);
            }
            else
            {

                OnHit(begin, config, state, hitInfo, fsm);
            }
            return true;
        }
        return false;
        
    }

    private void OnHit(Vector3 begin, HitConfig config, PlayerState state, RaycastHit hitInfo, FSM fsm)
    {
        //1、命中特效
        //2、设置特效位置 特效朝向

        if (fsm != null && hit_targets.Contains(fsm.instance_id) == false)
        {

            var go = ResourceManager.Instance.Create_Hit_Effect(config.hitObj, hitInfo.point, hitInfo.normal);

            //这里新增一个 防止 挥刀的delta 被碰物体太小 而穿过去的bug
            var value = AttHelper.Instance.Damage(this.player, state, fsm);
            //3、计算 扣除血量 (这一步可以给对方来做);
            fsm.UpdateHP_OnHit(value); 
            //4、通知对方受击 也就是常说的 我bit你啊 扑街
            var fd = fsm._transform.ForwardOrBack(begin) > 0 ? 0 : 1;
            if (fsm.att_base.hp > 0)
            {
                if(state.skill.add_fly != null)
                {
                    fsm.OnBash(fd,this.player,state.skill.add_fly,hitInfo.point);
                }
                else
                {
                    fsm.OnHit(fd, this.player);

                }
            }
            else
            {
                fsm.OnDeath(fd, this.player);
            }
            player.Attack_Hitlag(state);

            //6、命中音效
            string path = CombatConfig.Instace.GetConfig().hit_audio_path;
            AudioController.Instace.Play(path, hitInfo.point);
            //5、更新血条
        }
    }

    private void OnBeBlock(RaycastHit hitInfo, FSM fsm)
    {
        //1、格挡特效
        if (fsm != null && hit_targets.Contains(fsm.instance_id) == false)
        {
            hit_targets.Add(fsm.instance_id);
            var effectPath = CombatConfig.Instace.GetConfig().block_effect_path;
            var effect = ResourceManager.Instance.Create_Hit_Effect(effectPath, hitInfo.point, hitInfo.normal);
            //2、攻击方要进入弹反状态/处决状态/被振状态
            this.player.BeBlock(fsm);
            //3、格挡方 要进入格挡成功状态
            fsm.BlockSucess(this.player);
            //4、镜头模糊处理
            //5、音效
            var audioPath = CombatConfig.Instace.GetConfig().block_audio_path;
            AudioController.Instace.Play(audioPath, hitInfo.point);
        }

    }

    public override void ReLoop(PlayerState state)
    {
        base.ReLoop(state);
    }

    public override void ReStart(PlayerState state)
    {
        base.ReStart(state);
    }
}